#include "MiscUtils/TdrMisc/Headers/TConfiger.hpp"
#include "MiscUtils/TdrMisc/Headers/tFile.hpp"
#include "MiscUtils/TdrMisc/Headers/tLogger.hpp"
#include "MiscUtils/TdrMisc/Headers/tFormatter.hpp"
#include "Libs/SimpleJSON/JSON.hpp"

//#include <filesystem>
#include <iostream>
#include<Windows.h>

std::wstring TConfiger::filenameCore = L".tcfg";
std::wstring TConfiger::filename;
void* TConfiger::cfg = nullptr;

using namespace std;

JSONValue* getEntry(void* rootV, std::wstring myNamespace, std::wstring majorName, std::wstring minorName) {
	if (rootV == nullptr) {
		return nullptr;
	}
	JSONObject root = ((JSONValue*)rootV)->AsObject();
	if (root.find(myNamespace) != root.end()) {
		JSONObject ns = root[myNamespace]->AsObject();
		if (ns.find(majorName) != ns.end()) {
			if (minorName.length() == 0) {
				return ns[majorName];
			}
			else {
				JSONObject mj = ns[majorName]->AsObject();
				if (mj.find(minorName) != mj.end()) {
					return mj[minorName];
				}
				else {
					TLogger::writeLine(L"Minor key " + minorName + L" not found");
				}
			}
		}
		else {
			TLogger::writeLine(L"Major key " + majorName + L" not found");
		}
	}
	else {
		TLogger::writeLine(L"Namespace " + myNamespace + L" not found");
	}

	return nullptr;
}

void TConfiger::init() {
	if (filename.length() == 0) {
		wchar_t path[MAX_PATH];

		if (GetModuleFileName(0, path, sizeof path))
		{
			wstring dir = TFile::getDirNoFilenameOnly(path);

			filename = wstring(dir) + filenameCore;
			wstring txt = TReadFromTxt::readAllWText(filename);
			TLogger::writeLine("tConfig File Loaded. Size: " + TFormater::int2str(txt.length()));
			JSONValue* jVal = JSON::Parse(txt.c_str());
			if (jVal == nullptr) {
				TLogger::writeLine(L"tConfig File parse failed: " + filename);
				return;
			}
			if (!jVal->IsObject()) {
				TLogger::writeLine(L"tConfig File not Object");
				delete jVal;
				return;
			}
			TLogger::writeLine(L"tConfig File loaded");
			JSONObject root = jVal->AsObject();

			if (root.find(L"name") != root.end()) {
				TLogger::writeLine(L"Name: " + root[L"name"]->AsString());
			}

			cfg = jVal;
		}
	}
}

int TConfiger::getIntFlag(std::wstring myNamespace, std::wstring majorName, std::wstring minorName, int defaultValue) {
	JSONValue* entry = getEntry(cfg, myNamespace, majorName, minorName);

	if (entry == nullptr) {
		TLogger::writeLine(L"tConfig entry not found: " + myNamespace + L"::" + majorName + L":" + minorName);
		return defaultValue;
	}
	else {
		TLogger::write(L"tConfig loaded: " + myNamespace + L"::" + majorName + L":" + minorName);
		int ret = entry->AsNumber();
		TLogger::writeLine(L"Of " + TWFormater::int2str(ret));
		return ret;
	}
}

bool TConfiger::getFloatVals(std::wstring myNamespace, std::wstring majorName, std::wstring minorName, float* arrayWithDefaults, int size) {
	JSONValue* entry = getEntry(cfg, myNamespace, majorName, minorName);

	if (entry == nullptr) {
		TLogger::writeLine(L"tConfig entry not found: " + myNamespace + L"::" + majorName + L":" + minorName);
		return false;
	}
	else {
		TLogger::writeLine(L"tConfig loaded: " + myNamespace + L"::" + majorName + L":" + minorName);
		auto arrayWStr = entry->AsString();
		auto arrayStr = TFormater::wstring2string(arrayWStr);
		int count = TFormater::str2floats(arrayStr, arrayWithDefaults, size, ',');
		TLogger::writeLine(L"Of " + TWFormater::int2str(count));
		return true;
	}
}

bool TConfiger::getStringVal(std::wstring myNamespace, std::wstring majorName, std::wstring minorName, std::string& val) {
	JSONValue* entry = getEntry(cfg, myNamespace, majorName, minorName);

	if (entry == nullptr) {
		TLogger::writeLine(L"tConfig entry not found: " + myNamespace + L"::" + majorName + L":" + minorName);
		return false;
	}
	else {
		TLogger::writeLine(L"tConfig loaded: " + myNamespace + L"::" + majorName + L":" + minorName);
		auto wStr = entry->AsString();
		val = TFormater::wstring2string(wStr);
		TLogger::writeLine("Of " + val);
		return true;
	}
}

std::vector<std::wstring> TConfiger::getMinorEntries(std::wstring myNamespace, std::wstring majorName) {
	std::vector<std::wstring> ret;

	if (cfg == nullptr) {
		return ret;
	}
	JSONObject root = ((JSONValue*)cfg)->AsObject();
	if (root.find(myNamespace) != root.end()) {
		JSONObject ns = root[myNamespace]->AsObject();
		if (ns.find(majorName) != ns.end()) {
			JSONObject mj = ns[majorName]->AsObject();
			for (auto& item : mj) {
				ret.push_back(item.first);
			}
			return ret;
		}
		else {
			return ret;
		}
	}
	else {
		return ret;
	}


	return ret;
}

/*
Used configs
namespace: "sComposer"
  major: L"overwriteThreadNumber"

namespace: "sScanner"
  major: L"sampleMarginTBLRMm"
*/